/* Copyright (c) 2022, TD SYNNEX Corporation. All rights reserved */

package com.example.bootintegration.dao.jpa.repository;

import jakarta.persistence.EntityManager;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;

/**
 * @see SimpleJpaRepository entityInformation
 */
@SuppressWarnings("rawtypes")
public class SimpleJpaRepositoryUtil {

    private static final String ENTITY_INFORMATION = "entityInformation";
    private static final String EM = "entityManager";

    private static final Field ENTITY_INFORMATION_FEILD = getAccessibleFeild(SimpleJpaRepository.class, ENTITY_INFORMATION);
    private static final Field EM_FEILD = getAccessibleFeild(SimpleJpaRepository.class, EM);

    public static EntityManager getEntityManager() {
        SimpleJpaRepository simpleJpaRepository = (SimpleJpaRepository) ExposeInvocationInterceptor.currentInvocation().getThis();
        return getEntityManager(simpleJpaRepository);
    }

    public static EntityInformation<?, ?> getEntityInformation() {
        SimpleJpaRepository simpleJpaRepository = (SimpleJpaRepository) ExposeInvocationInterceptor.currentInvocation().getThis();
        return getEntityInformation(simpleJpaRepository);
    }

    /**
     * @param simpleJpaRepository
     * @return
     * @throws IllegalArgumentException simpleJpaRepository is not instanceof SimpleJpaRepository
     * @throws IllegalAccessException
     * @see SimpleJpaRepository entityInformation
     */
    @SuppressWarnings("unchecked")
    public static <T, ID> EntityInformation<T, ID> getEntityInformation(Object simpleJpaRepository) {
        try {
            Object entityInformation = ENTITY_INFORMATION_FEILD.get(simpleJpaRepository);
            return (EntityInformation<T, ID>) entityInformation;
        } catch (IllegalArgumentException | IllegalAccessException e) {
            throw new InvalidDataAccessApiUsageException("SimpleJpaRepository#getEntityInformation error", e);
        }
    }



    public static EntityManager getEntityManager(Object simpleJpaRepository) {
        try {
            Object em = EM_FEILD.get(simpleJpaRepository);
            return (EntityManager) em;
        } catch (IllegalArgumentException | IllegalAccessException e) {
            throw new InvalidDataAccessApiUsageException("SimpleJpaRepository#getEm error", e);
        }
    }

    public static Field getAccessibleFeild(Class<?> clazz, String declaredField) {
        try {
            Field field = clazz.getDeclaredField(declaredField);
            ReflectionUtils.makeAccessible(field);
            return field;
        } catch (NoSuchFieldException e) {
            throw new IllegalStateException(e);
        }
    }

}
